/**
 * https://js.devexpress.com/Vue/Documentation/ApiReference/UI_Components/dxDataGrid/Configuration/columnFixing/texts/#unfix
 * 本文件不引用devextreme任何文件，因为引用方式可能与外界不一致。
 * devextreme-vue v23.2.11
 * devextreme-vue v24.1.7
 * 
 */
import acroMLClassMethod from './acroML.ClassMethod.mjs';

let DDKeys,switchLocale;
let classMethods={};

function init(ops){
  /**
   * DDKeys是英文下的文本,是平面的，类似：
    {
     en：{
        Back: "Back"
        Cancel: "Cancel"
        CheckState: "Check state"
        Clear: "Clear"
        Close: "Close"
        Done: "Done"
        Loading: "Loading..."
        No: "No"
        OK: "OK"
        Search: "Search"
        Select: "Select..."
        Today: "Today"
        Yes: "Yes"
        Yesterday: "Yesterday"
        dxAvatar-defaultImageAlt: "Avatar"
        dxCalendar-ariaWidgetName: "Calendar"
        dxCalendar-captionCenturyLabel: "Century selection"
        dxCalendar-captionDecadeLabel: "Decade selection"
        dxCalendar-captionMonthLabel: "Month selection"
        dxCalendar-captionYearLabel: "Year selection"
      }
    }
   * 用不上
   */
  DDKeys=ops.DDKeys;
  //console.log(DDKeys);
  switchLocale=ops.switchLocale;
}

function isObject(value){
  if (!value) return false;
  return (typeof value==='object') && 
    !(Array.isArray(value)) && 
    (Object.prototype.toString.call(value) !== '[object Date]') &&
    (Object.prototype.toString.call(value) !== '[object RegExp]');
}
/**
 * 参数更新模式：全部一次更新，一次更新一个
 */
const OPTIONAPPLYMODE=['all','one'][1];
function wrap_transDevextremeCom(proc){
  return function(t,instWrap){
    let inst=instWrap.$_instance;
    if (!inst){
      return;
    }
    let options;
    let state;
    if (inst.state) state=inst.state();
    let defaultValues=inst._getDefaultOptions();
    /**
     * 切换到英文，不英文下的文本作为DDKey原语
     */
    let tag=switchLocale();
    switchLocale('en');
    let defaultDDKeys=inst._getDefaultOptions();
    switchLocale(tag);
    const OPTIONGETMode=['optionManager','optionFunction'][1];
    if (OPTIONGETMode=='optionManager'){
      options=inst._options._optionManager._options;
    }
    else{
      // inst._options._default=defaultOps;
      // inst._options._initialOptions=defaultOps;
      // if (inst.NAME=='dxDataGrid'){
      //   console.log(1,defaultOps);
      // }
      options=inst.option();
    }
    //if (inst.NAME=='dxDataGrid') console.log(2,options);
    /**
     * inst.option()返回的类型是object，不知为何修改placeholder后用inst.option(options)放回去不生效。
     * 但是inst.option({'placeholder':'上海'});或inst.option('placeholder','上海');会刷新。
     * http://192.168.10.133:8081/bug-view-2056.html
     * 必须在修改前用JSON.parse(JSON.stringify(options))或options={...options}处理一下。
     * 有一个警告：error:35 W0001 - dxPopup - 'closeOnOutsideClick' option is deprecated in 22.1. Use the 'hideOnOutsideClick' option instead.
     */
    //options=JSON.parse(JSON.stringify(options));
    options={...options};
    function removeWarning(){
      // let deprecatedOptions=inst._getDeprecatedOptions();
      // console.log(deprecatedOptions);
      let deleteProps=[];
      let scanedObjs=[];
      function removeNoneStringProps(obj){
        if (!obj) return;
        for(let propName in obj){
          let value=obj[propName];
          //console.log(propName);
          if (isObject(value)){
            if (scanedObjs.indexOf(value)<0){
              scanedObjs.push(value);
              removeNoneStringProps(value);
            }
          }
          else if (typeof value!=='string') deleteProps.push({obj,propName})
        }
      }
      removeNoneStringProps(options);
      for(let i=0;i<deleteProps.length;i++){
        delete deleteProps[i].obj[deleteProps[i].propName];
      }
      // if (options.dropDownOptions) delete options.dropDownOptions.closeOnOutsideClick;
    }
    inst.beginUpdate();
    try{
      function restoreStub(){
        if (instWrap._acroml_stub){        
          function copyStub(stub,obj){
            obj._acroml_=stub._acroml_;
            for(let propName in stub){
              if (propName=='_acroml_') continue;
              let stubValue=stub[propName];
              let objValue=obj[propName];
              if (objValue) copyStub(stubValue,objValue);
            }
          }
          copyStub(instWrap._acroml_stub,options)
        }
      }
      let fullPropName='';
      let ops={
        t,instWrap,options,fullPropName,defaultDDKeys,defaultValues,
        inst,
        translateNodeArrayObject(nodeNames,itemNodeNames,itemProc){
          let self=this;
          self.nodeNames=nodeNames;
          self.itemNodeNames=itemNodeNames;
          self.itemProc=itemProc;
          dx_translateNodeArrayObject(self);
        },
        translateProp(propName,defaultDDKey0,defaultValue0){
          let self=this;
          let defaultDDKey=defaultDDKey0||(defaultDDKeys?defaultDDKeys[propName]:undefined);
          let defaultValue=defaultValue0||(defaultValues?defaultValues[propName]:undefined);
          self.propName=propName;
          self.defaultDDKey=defaultDDKey;
          self.defaultValue=defaultValue;
          dx_translateProp(self);
        },
        translateProps(propNames){
          let self=this;
          self.propNames=propNames;
          dx_translateProps(self);
        },
        translateNodeProps(nodeNames,propNames){
          let self=this;
          self.nodeNames=nodeNames;
          self.propNames=propNames;
          dx_translateNodeProps(self);
        }
      }
      proc(ops);
      function saveStub(){
        /**
         * 保存翻译前数据。一个个更新属性。
         * 层级太多，扫描很慢。
         */
        let stub={};
        let scanedObjs=[];
        function applyProps(obj,parentPropName,objStub,level){
          if (scanedObjs.indexOf(obj)>=0) return;
          scanedObjs.push(obj);
          objStub._acroml_=obj._acroml_;
          level++;
          for(let propName in obj){
            if (propName=='_acroml_') continue;
            let propValue=obj[propName];
            let fullPropName=(parentPropName?(parentPropName+'.'):'')+propName;
            if (isObject(propValue)){
              objStub[propName]={};
              //console.log({level,fullPropName});
              applyProps(propValue,fullPropName,objStub[propName],level);
            }
            else if (obj._acroml_ && obj._acroml_[propName]){
              //console.log(fullPropName,propValue,propName);
              inst.option(fullPropName,propValue);
            }
          }
        }
        applyProps(options,null,stub,0);
        instWrap._acroml_stub=stub;
        function cleanProps(obj){
          if (!obj._acroml_) return false;
          
          let notScanedProps=[];
          for(let propName in obj){
            if (propName=='_acroml_') continue;
            let propValue=obj[propName];
            if (isObject(propValue)){
              if (!cleanProps(propValue)){
                //notScanedProps.push(propName);
              }
            }
            else if (!obj._acroml_[propName]){
              notScanedProps.push(propName);
            }
          }
          //console.log('******111111111111111111111111111111111111',notScanedProps);
          for(let i=0;i<notScanedProps.length;i++){
            let propName=notScanedProps[i];
            delete obj[propName];
          }
          return true;
        }
        if (cleanProps(options)){
          for(let propName in options){
            if (propName=='_acroml_') continue;
            let propValue=options[propName];
            console.log('******111111111111111111111111111111111111',propName,propValue);
            inst.option(propName,propValue);
          }
        }

        for(let propName in options){
          if (propName=='_acroml_') continue;
          let propValue=options[propName];
          if (isObject(propValue)) console.log(propName,propValue);
          if (options._acroml_[propName]||isObject(propValue)){
            inst.option(propName,propValue);
          }
          // if (!options._acroml_[propName] && !isObject(propValue)){
          //   notScanedProps.push(propName);
          // }
        }
        console.log('&&&&&&&&&&&&&',notScanedProps);
        for(let i=0;i<notScanedProps.length;i++){
          let propName=notScanedProps[i];
          delete options[propName];
        }
      }
      /**
       * 不整体更新，用inst.option(name,value)单个更新。
       * 如果整体更新，可能会导致组件重建。
       */
      if (OPTIONAPPLYMODE=='all') inst.option(options);
      /**设置预设参数可能丢掉了状态，恢复 */
      if (state) inst.state(state);
    }
    finally{
      inst.endUpdate();
      //inst.repaint();
    }
  }
}

function dx_translateProp(ops){
  /**
   * 从实例上读取翻译前数据到当前要翻译的options上
   */
  let stub;
  let fullPropName=(ops.fullPropName?(ops.fullPropName+'.'):'')+ops.propName;
  if (ops.instWrap){
    stub=ops.instWrap._acroml_stub;
    if (stub){
      ops.options._acroml_=stub[fullPropName];
    }
  }
  acroMLClassMethod.translateProp(ops.t,ops.options,ops.propName,ops.defaultDDKey,ops.defaultValue);
  /**
   * 更新属性值
   */
  if (OPTIONAPPLYMODE=='one'){
    if (ops.inst) ops.inst.option(fullPropName,ops.options[ops.propName]);
  }
  if (ops.instWrap){
    /**
     * 把翻译前原始数据保存到实例上，切换语言时需要
     */
    if (ops.instWrap && ops.options._acroml_){
      if (!stub){
        stub={};
        ops.instWrap._acroml_stub=stub;
      }
      stub[fullPropName]=ops.options._acroml_;
    }
  }
}

function dx_translateProps({
  t,instWrap,inst,options,fullPropName,
  propNames,defaultDDKeys,defaultValues
}){
  if (!options) return;
  if (!propNames){
    propNames=[];
    let copyObj=defaultDDKeys||options;
    for(let propName in copyObj) propNames.push(propName);
  }
  for(let i=0;i<propNames.length;i++){
    let propName=propNames[i];
    let defaultDDKey=defaultDDKeys?defaultDDKeys[propName]:undefined;
    let defaultValue=defaultValues?defaultValues[propName]:undefined;
    dx_translateProp({
      t,instWrap,inst,options,fullPropName,
      propName,defaultDDKey,defaultValue
    });
  }
}

function getNodeOps(ops){
  if (!ops.options) return{};
  let options=ops.options;
  let defaultDDKeys=ops.defaultDDKeys;
  let defaultValues=ops.defaultValues;
  let fullPropName=ops.fullPropName;
  for(let i=0;i<ops.nodeNames.length;i++){
    let nodeName=ops.nodeNames[i];
    fullPropName=(fullPropName?(fullPropName+'.'):'')+nodeName;
    options=options[nodeName];
    if (!options) break;
    if (typeof options=='string'){
      //console.log('options should be object,but is string:',options);
      /**
       * uistudio汇出的组件中，可能某些属性是这样的：
       * "editor-options": "{ placeholder: 'Search column' }"
       * JSON.parse无法解析，只能用eval
       */
      options=eval(`(${options})`);
    }
    if (defaultDDKeys){
      defaultDDKeys=defaultDDKeys[nodeName];
    }
    if (defaultValues){
      defaultValues=defaultValues[nodeName];
    }
  }
  return {options,fullPropName,defaultDDKeys,defaultValues}
}

function dx_translateNodeProps(ops){
  let ops1=getNodeOps(ops);
  if (!ops1.options) return;
  let ops2=Object.assign({},ops,ops1);
  /**
   * inst赋值null，之后，dx_translateProps不会单独更新个别属性值
   */
  ops2.inst=null;
  dx_translateProps(ops2);
  if (OPTIONAPPLYMODE=='one'){
    if (ops.inst) ops.inst.option(ops2.fullPropName,ops2.options);
  }
}

function dx_translateNodeArrayObject(ops){
  //console.log('1',ops.nodeNames);
  let ops2=Object.assign({},ops,getNodeOps(ops));
  if (!ops2.options) return;
  ops2.instWrap=null;
  ops2.inst=null;
  for(let i=0;i<ops2.options.length;i++){
    let ops3=Object.assign({},ops2);
    ops3.options=ops2.options[i];
    if (ops.itemNodeNames){
      for(let j=0;j<ops.itemNodeNames.length;j++){
        if (!ops3.options) break;
        ops3.options=ops3.options[ops.itemNodeNames[j]];
      }
    }
    ops.itemProc(ops3);
  }
  if (OPTIONAPPLYMODE=='one'){
    if (ops.inst){
      ops.inst.option(ops2.fullPropName,ops2.options);
    }
  }
}

function t_DxTextBox(ops){
  ops.translateProps(['hint','placeholder','label','maskInvalidMessage']);
  ops.translateNodeArrayObject(['buttons'],['options'],t_DxButton);
}

function t_DxNumberBox(ops){
  ops.translateProps(['hint','placeholder','label','invalidValueMessage']);
  ops.translateNodeArrayObject(['buttons'],['options'],t_DxButton);
}

function t_DxDataGrid(ops){
  //console.log('t_DxDataGrid',instWrap);
  /**
   * 不要企图通过instWrap.$.props去修改参数，因为DxDataGrid的某些参数有2种写法：
   * (1)<DxDataGrid searchPanel="{visible:true,placeholder:'search...'}"><DxDataGrid>
   * (2)<DxDataGrid><DxSearchPanel visible='true' placeholder='search...' /><DxDataGrid>
   * 用instWrap.$.props时，第2种写法的参数是找不到的。
   * 不能通过coumns属性更新column的caption，因为<DxDataGrid><DxColumn dataField='ID />这种写法，columns属性为空
   * 必须通过method:columnOption来更新column的caption
   */
  ops.translateProps(['hint','noDataText']);

  ops.translateNodeProps(
    ['loadPanel'],
    ['text']
  );
  
  ops.translateNodeProps(
    ['columnChooser'],
    ['emptyPanelText','title']
  );

  ops.translateNodeProps(
    ['columnChooser','search','editorOptions'],
    ['placeholder']
  );

  ops.translateNodeProps(
    ['columnFixing','texts'],
    ['fix','leftPosition','rightPosition','unfix']
  );

  ops.translateNodeProps(
    ['editing','texts'],
    ['addRow','cancelAllChanges','cancelRowChanges','confirmDeleteMessage',
      'confirmDeleteTitle','deleteRow','editRow','saveAllChanges',
      'saveRowChanges','undeleteRow','validationCancelChanges'
    ]
  );

  ops.translateNodeProps(
    ['export','texts'],
    ['exportAll','exportSelectedRows','exportTo']
  );

  ops.translateNodeProps(
    ['filterPanel','texts'],
    ['clearFilter','createFilter','filterEnabledHint']
  );

  ops.translateNodeProps(
    ['filterRow'],
    ['applyFilterText','betweenEndText','betweenStartText','resetOperationText',
      'showAllText']
  );

  ops.translateNodeProps(
    ['groupPanel'],
    ['emptyPanelText']
  );

  ops.translateNodeProps(
    ['grouping','texts'],
    ['groupByThisColumn','groupContinuedMessage','groupContinuesMessage',
      'ungroup','ungroupAll']
  );

  ops.translateNodeProps(
    ['headerFilter','texts'],
    ['cancel','emptyValue','ok']
  );

  ops.translateNodeProps(
    ['pager'],
    ['inforText']
  );
  
  ops.translateNodeProps(
    ['searchPanel'],
    ['placeholder']
  );

  ops.translateNodeProps(
    ['sorting'],
    ['ascendingText','clearText','descendingText']
  );

  ops.translateNodeProps(
    ['summary','texts'],
    ['avg','avgOtherColumn','count','max','maxOtherColumn','min','minOtherColumn',
      'sum','sumOtherColumn']
  );

  ops.translateNodeArrayObject(['columns'],null,t_DxColumn);
}

function t_DxColumn(ops){
  ops.translateProp('caption',null,ops.options.dataField);
  ops.translateProps(['trueText','falseText']);
}

function t_DxButton(ops){
  //console.log('t_DxButton',ops);
  ops.translateProps(['hint','text']);
}

function t_DxCheckBox(ops){
  ops.translateProps(['hint','text']);
}

function t_DxColorBox(ops){
  ops.translateProps([
    'hint','label','placeholder','applyButtonText','cancelButtonText'
  ]);
}

function t_DxDateBox(ops){
  ops.translateProps([
    'hint','label','placeholder','applyButtonText',
    'cancelButtonText','todayButtonText'
  ]);
}

function t_DxDropDownBox(ops){
  ops.translateProps(['hint','label','placeholder']);
}
function t_DxTabPanelItem(ops){
  ops.translateProps(['title']);
}
function t_DxTabPanel(ops){
  ops.translateProps(['hint','noDataText']);
  ops.translateNodeArrayObject(['items'],null,t_DxTabPanelItem);
}

function t_DxTabsItem(ops){
  ops.translateProps(['text']);
}

function t_DxTabs(ops){
  ops.translateProps(['hint','noDataText']);
  ops.translateNodeArrayObject(['items'],null,t_DxTabsItem);
}

function t_DxToolbar(ops){
  ops.translateProps(['hint','noDataText']);
  ops.translateNodeArrayObject(['items'],null,
    function(ops2){
      let item=ops2.options;
      let m=classMethods[item.widget];
      if (m){
        ops2.options=item.options;
        m(ops2);
      }
    }
  );
}

function t_DxSelectBoxItem(ops){
  ops.translateProps(['text']);
}

function t_DxSelectBox(ops){
  ops.translateProps(['hint','noDataText','placeholder']);
  ops.translateNodeArrayObject(['items'],null,t_DxSelectBoxItem);
}

function t_DxChart(ops){
  if (typeof ops.options.title=='string') 
    ops.translateProps(['title']);
  else if (ops.options.title){
    ops.translateNodeProps(['title'],['text']);
    if (typeof ops.options.title.subtitle=='string') 
      ops.translateNodeProps(['title'],['subtitle']);
    else
      ops.translateNodeProps(['title','subtitle'],['text']);
  }

  if (typeof ops.options.argumentAxis.title=='string') 
    ops.translateNodeProps(['argumentAxis'],['title']);
  else
    ops.translateNodeProps(['argumentAxis','title'],['text']);
  
  ops.translateNodeArrayObject(['valueAxis'],null,
    function(ops2){
      let axis=ops2.options;
      if (typeof axis.title=='string') 
        ops2.translateProps(['title']);
      else
        ops2.translateNodeProps(['title'],['text']);
    }
  );
}

function t_DxPivotGrid(ops){
  //console.log('t_DxPivotGrid',instWrap,options);
  ops.translateProps(['hint']);
  /**
   * translateNodeProps的第4个参数propNames，
   * 如果全部属性都是内建字串，不是非内建字串全靠用户设置，也可以给null，就从内建defaultDDKeys提取，适应性更强。
   */
  ops.translateNodeProps(
    ['texts'],
    ['collapseAll','dataNotAvailable','expandAll','exportToExcel','grandTotal',
      'noData','removeAllSorting','showFieldChooser','sortColumnBySummary',
      'sortRowBySummary','total'
    ]
  );
  ops.translateNodeProps(
    ['fieldChooser'],
    ['title']
  );
  /**
   * fieldChooser的texts是空，bug？导致切换语言后不能翻译。fix:给它加上。
        "dxPivotGrid-rowFields": "Row Fields",
        "dxPivotGrid-columnFields": "Column Fields",
        "dxPivotGrid-dataFields": "Data Fields",
        "dxPivotGrid-filterFields": "Filter Fields",
        "dxPivotGrid-allFields": "All Fields",
   */
  if (!ops.options.fieldChooser.texts){
    //console.log(ops);
    ops.options.fieldChooser.texts={
      allFields:"All Fields",
      columnFields:"Column Fields",
      dataFields:"Data Fields",
      filterFields:"Filter Fields",
      rowFields:"Row Fields"
    };
  }
  ops.translateNodeProps(
    ['fieldChooser','texts'],
    ['allFields','columnFields','dataFields','filterFields','rowFields']
  );
  ops.translateNodeProps(
    ['fieldPanel','texts'],
    ['columnFieldArea','dataFieldArea','filterFieldArea','rowFieldArea']
  );
  ops.translateNodeProps(
    ['headerFilter','texts'],
    ['cancel','emptyValue','ok']
  );
  ops.translateNodeProps(
    ['loadPanel'],
    ['text']
  );

  ops.translateNodeArrayObject(['dataSource','_fields'],null,t_DxColumn);
}

function t_DxPopup(ops){
  //console.log('t_DxPopup',instWrap,options);
  ops.translateProps(['title']);
  ops.translateNodeArrayObject(['toolbarItems'],null,function(ops2){
    let item=ops2.options;
    let m=classMethods[item.widget];
    if (m){
      ops2.options=item.options;
      m(ops2);
    }
  })
}

function register(c,m){
  classMethods[c]=m;
  acroMLClassMethod.register(c,wrap_transDevextremeCom(m));
}

register('dxTextBox',t_DxTextBox);
register('dxDataGrid',t_DxDataGrid);
register('dxButton',t_DxButton);
register('dxCheckBox',t_DxCheckBox);
register('dxColorBox',t_DxColorBox);
register('dxDateBox',t_DxDateBox);
register('dxDropDownBox',t_DxDropDownBox);
register('dxTabPanel',t_DxTabPanel);
register('dxTabs',t_DxTabs);
//同时注册DxToolbar和t_DxSelectBox后，某个DataGrid无法一开始翻译。已解决。
register('dxToolbar',t_DxToolbar);
register('dxSelectBox',t_DxSelectBox);
register('dxNumberBox',t_DxNumberBox);
register('dxChart',t_DxChart);
register('dxPivotGrid',t_DxPivotGrid);
register('dxPopup',t_DxPopup);
/**
 * 注册devextreme组件类别的名称获取方法。
 * 否则：register用组件类别注册的话，需要先引入组件，这导致2个问题：
 * （1）引入的组件可能不会被使用，浪费
 * （2）引入方式（打包引入或单独引入，或引入路径是否带文件扩展名）可能跟外部不一致；
 */
acroMLClassMethod.registerClassNameGetter(function(instWrap){
  let className;
  if (instWrap.$_instance) className=instWrap.$_instance.NAME;
  if (!className) className=instWrap.widget;
  //if (!className) className=instWrap.$options.$_optionName;
  return className;
});

acroMLClassMethod.registerRendorHandler(function(t,instWrap){
  let className;
  if (instWrap.$_instance) className=instWrap.$_instance.NAME;
  if (!className) className=instWrap.widget;
  if (className){
    let m=classMethods[className];
    if (m){
      let m2=wrap_transDevextremeCom(m);
      m2(t,instWrap);
      return true;
    }
  }
  return false;
});

export default {init,t_DxDataGrid,t_DxTextBox};
export {init,t_DxDataGrid,t_DxTextBox};